﻿using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.IO;
using SuuntoAmbitConnector;
using System.Xml;

namespace SuuntoAmbitConnectorTests
{
    [TestClass]
    public class SuuntoAmbitFileReaderTests
    {
        private string suuntoAmbitWorkoutRepository = @"..\..\SuuntoAmbitTestWorkoutFiles\";


        /*
         * 
         * Accessing and reading suunto files tests
         * 
         */

        [TestMethod]
        public void TestSuuntoAmbitRepositoryExists()
        {            
            var suuntoFileReader = new SuuntoAmbitFileReader(suuntoAmbitWorkoutRepository);

            Assert.IsTrue(suuntoFileReader.HasWorkoutFiles, "There are no Suunto Ambit workout files in {0}", suuntoAmbitWorkoutRepository);
        }

        [TestMethod]
        [ExpectedException(typeof(DirectoryNotFoundException))]
        public void TestInvalidSuuntoAmbitWorkoutRepositoryThrowsDirectoryNotFoundException()
        {
            var suuntoFileReader = new SuuntoAmbitFileReader(@"folder\which\doesnt\exist\");

            var expectedExceptionOccurs = suuntoFileReader.HasWorkoutFiles;
        }
                
        [TestMethod]
        [ExpectedException(typeof(FileNotFoundException))]
        public void TestSuuntoAmbitWorkoutFileDoesNotExistThrowsFileNotFoundException()
        {
            var suuntoFileReader = new SuuntoAmbitFileReader(suuntoAmbitWorkoutRepository);
            
            suuntoFileReader.ReadWorkoutFileAsXml("fileWhichDoesntExist.wtf");
        }

        [TestMethod]
        public void TestReadSuuntoAmbitFileAsXml()
        {
            var suuntoFileReader = new SuuntoAmbitFileReader(suuntoAmbitWorkoutRepository);
            var expectedXmlFile = suuntoFileReader.ReadWorkoutFileAsXml("suuntoAmbitWorkout_OneMove.xml");

            Assert.AreEqual("Duration", expectedXmlFile.SelectSingleNode("root/header/Duration").Name, 
                "Unable to find a <Duration> element in <header>");
        }

        [TestMethod]
        [ExpectedException(typeof(InvalidOperationException))]
        public void TestReadSingleValueThrowsInvalidOperationExceptionWhenWorkoutFileHasNotBeenLoaded()
        {
            var suuntofileReader = new SuuntoAmbitFileReader(suuntoAmbitWorkoutRepository);
            var durationValue = long.Parse(suuntofileReader.ReadSingleValue("Duration"));
        }

        [TestMethod]
        [ExpectedException(typeof(FileNotFoundException))]
        public void TestLoadWorkoutFileThrowsFileNotFoundExceptionWhenWorkoutFileDoesNotExist()
        {
            var suuntofileReader = new SuuntoAmbitFileReader(suuntoAmbitWorkoutRepository);

            suuntofileReader.LoadWorkoutFile("fileWhichDoesntExist.wtf");
        }

        [TestMethod]
        public void TestLoadWorkoutFile()
        {
            var suuntofileReader = new SuuntoAmbitFileReader(suuntoAmbitWorkoutRepository);
            suuntofileReader.LoadWorkoutFile("suuntoAmbitWorkout_OneMove.xml");

            Assert.IsTrue(suuntofileReader.IsWorkoutFileLoaded);
            Assert.AreEqual("suuntoAmbitWorkout_OneMove.xml", suuntofileReader.GetWorkoutFileName());
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void TestReadSingleValueThrowsArgumentExceptionWhenNodeNameIsEmpty()
        {
            var suuntofileReader = new SuuntoAmbitFileReader(suuntoAmbitWorkoutRepository);
            suuntofileReader.LoadWorkoutFile("suuntoAmbitWorkout_OneMove.xml");

            suuntofileReader.ReadSingleValue("");          
        }

        [TestMethod]
        public void TestReadSingleValue()
        {
            var suuntofileReader = new SuuntoAmbitFileReader(suuntoAmbitWorkoutRepository);
            suuntofileReader.LoadWorkoutFile("suuntoAmbitWorkout_OneMove.xml");
            
            var durationValue = suuntofileReader.ReadSingleValue("Activity");

            Assert.AreEqual("Cycling", durationValue, "Unexpected value read");
        }

        [TestMethod]
        public void TestReadValueAsInt()
        {
            var suuntofileReader = new SuuntoAmbitFileReader(suuntoAmbitWorkoutRepository);
            suuntofileReader.LoadWorkoutFile("suuntoAmbitWorkout_OneMove.xml");

            int durationValue = suuntofileReader.ReadSingleValueAsInt("ActivityType");

            Assert.AreEqual(4, durationValue, "Unexpected activity type value");
        }

        [TestMethod]
        public void TestReadValueAsDouble()
        {
            var suuntofileReader = new SuuntoAmbitFileReader(suuntoAmbitWorkoutRepository);
            suuntofileReader.LoadWorkoutFile("suuntoAmbitWorkout_OneMove.xml");

            double durationValue = suuntofileReader.ReadSingleValueAsDouble("Duration");
            
            Assert.AreEqual(1000, durationValue, "Unexpected duration value");
        }

        [TestMethod]
        public void TestReadValueAsDateTime()
        {
            var expectedStartDate = new DateTime(2013, 7, 11, 17, 23, 50);
            var suuntofileReader = new SuuntoAmbitFileReader(suuntoAmbitWorkoutRepository);
            suuntofileReader.LoadWorkoutFile("suuntoAmbitWorkout_OneMove.xml");

            var actualStartDate = suuntofileReader.ReadSingleValueAsDateTime("DateTime");

            Assert.AreEqual(expectedStartDate, actualStartDate, "Unexpected start date value");
        }

        [TestMethod]
        public void TestReadDuration()
        {
            var suuntofileReader = new SuuntoAmbitFileReader(suuntoAmbitWorkoutRepository);
            suuntofileReader.LoadWorkoutFile("suuntoAmbitWorkout_OneMove.xml");

            double durationValue = suuntofileReader.ReadDuration();
            
            Assert.AreEqual(1000, durationValue, "Unexpected duration value");
        }

        [TestMethod]
        public void TestReadDistance()
        {
            var suuntofileReader = new SuuntoAmbitFileReader(suuntoAmbitWorkoutRepository);
            suuntofileReader.LoadWorkoutFile("suuntoAmbitWorkout_OneMove.xml");

            double distanceValue = suuntofileReader.ReadDistance();
            
            Assert.AreEqual(16155, distanceValue, "Unexpected distance value");
        }

        

        /*
         * 
         * End-to-end connector tests 
         * 
         */

        [TestMethod]
        public void TestCreatingWorkoutObjectFromFileWithMinimumRequiredData()
        {
            var suuntofileReader = new SuuntoAmbitFileReader(suuntoAmbitWorkoutRepository);
            suuntofileReader.LoadWorkoutFile("suuntoAmbitWorkout_OneMove.xml");
            var expectedStartDate = new DateTime(2013, 7, 11, 17, 23, 50);
            var expectedActivity = 4;
            var expectedDuration = 1000;
            var expectedComment = "Created by Suunto2Endomondo";
                        
            var actualWorkout = suuntofileReader.CreateWorkoutObject();

            Assert.AreEqual(expectedStartDate, actualWorkout.StartDate, "Unexpected start date");
            Assert.AreEqual(expectedActivity, actualWorkout.Activity, "Unexpected activity");
            Assert.AreEqual(expectedDuration, actualWorkout.DurationInSeconds, "Unexpected duration");
            Assert.AreEqual(expectedComment, actualWorkout.Comment, "Unexpected comment");
        }

        [TestMethod]
        public void TestCreatingWorkoutObjectFromFileWithAdvancedData()
        {
            var suuntofileReader = new SuuntoAmbitFileReader(suuntoAmbitWorkoutRepository);
            suuntofileReader.LoadWorkoutFile("suuntoAmbitWorkout_OneMove.xml");
            var expectedStartDate = new DateTime(2013, 7, 11, 17, 23, 50);
            var expectedActivity = 4;
            var expectedDuration = 1000;
            var expectedDistance = 16155;
            var expectedComment = "Created by Suunto2Endomondo";

            var workout = suuntofileReader.CreateWorkoutObject();

            Assert.AreEqual(expectedStartDate, workout.StartDate, "Unexpected start date");
            Assert.AreEqual(expectedActivity, workout.Activity, "Unexpected activity");
            Assert.AreEqual(expectedDuration, workout.DurationInSeconds, "Unexpected duration");
            Assert.AreEqual(expectedDistance, workout.DistanceInMeters, "Unexpected distance");
            Assert.AreEqual(expectedComment, workout.Comment, "Unexpected comment");
        }
    }
}
